Chapter 3 Control
Condition Code
ZF SF 由最近一次的运算指令、比较指令结果决定
CF 表示无符号运算是否越界(向上溢出,向下借位),OF 为有符号溢出。二者的关系为相互不包含的关系。CF / OF 仅在对应 unsigned/signed 的加减乘运算指令、cmp 比较指令中被正确设置,位运算、test 比较指令均会被置零,除法指令中未定义,inc 和 dec 指令不影响 CF / OF
test 和 cmp 等价于没有赋值只修改条件码的运算指令。注意比较指令的操作数顺序同运算指令一样是反过来的。有 b w l q 四种后缀
条件码有三种使用方式
- 根据不同的组合修改某个 byte 的值
- 有条件地跳转
- 有条件地修改数据
Accessing the Condition Codes
Jump Instructions
Jump Instruction Encodings
在汇编码中可以以 label 的形式记录跳转,同文件内的跳转由汇编器处理,跨文件的跳转由链接器处理,最终所有跳跃指令都被正确地关联到可执行程序中对应的地址
PC- relative addressing (pointer counter relative addressing):
- 汇编语言中的 label 可以视为地址的一种包装
- 记录跳转指令地址 - 下一条指令地址,最长 4 bytes。在 64 位计算器上仅仅采用 32 位相对寻址是因为追求更短的代码长度,更高的 i-cache 吞吐量;大部分跳转都是局部跳转,过远的跳转由 indirect jump 支持;
Implementing Conditional Branches
if 语句的实现方式包括
- 条件跳转,根据条件跳转到不同地址执行不同的的指令块。跳转开销依赖于分支预测的正确性
- 条件赋值,提前计算两个方向的结果,并采用 cmov 指令根据条件相应地赋值。零跳转开销。不适用于:某一方向带有副作用,可能报错;计算开销超过 misprediction penalty 的情况。C++ 编译器仅在两方向的计算都很简单、没有副作用的情况下采用。一个重要不适用的例子
xp ? *xp : 0
。
Loop
do while = rep(do + test)
while = rep(test + do) = test + rep(do + test)
- jump to middle
- guarded do,此时通常可以优化掉第一个判断
for = init + rep(test + do + update) = init + test + rep(do + update + test) - continue 等价于跳转到 update
Switch Statement
采用 jump table 实现,首先下标标准化,然后在 jump table 各处赋值对应的语句块地址,跳转时采用 indirect jump: jmp *jptb(,idx, 8)。不清楚在 indirect jump 中作为内存地址身份出现的 jptb 标签是否仍然采用 PC-relative addressing,推测为否。另外,在汇编代码中竟然可以直接声明一个列表!